package com.weimob.mcloud.wechatwork.customer.mq.handler.losemsg;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.weimob.arch.artemis.client.api.consume.ArtemisMessage;
import com.weimob.arch.artemis.client.api.consume.ArtemisMessages;
import com.weimob.arch.artemis.client.spring.annotation.ArtemisMessageListener;
import com.weimob.arch.artemis.client.spring.annotation.Subscribe;
import com.weimob.arch.sub.env.application.annotation.SubEnvExposePoint;
import com.weimob.arch.sub.env.application.annotation.SubEnvTagExtractor;
import com.weimob.dq.client.annotation.DqListener;
import com.weimob.dq.core.entity.MsgPoolEntity;
import com.weimob.mcloud.wechatwork.core.base.SingleRequest;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.CustomerLoseLog;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerLoseService;
import com.weimob.mcloud.wechatwork.core.service.lbl.TaskService;
import com.weimob.mcloud.wechatwork.core.service.privatesphere.PrivateSphereService;
import com.weimob.mcloud.wechatwork.customer.config.DqConfig;
import com.weimob.mcloud.wechatwork.customer.domain.ArtemisBaseInfo;
import com.weimob.mcloud.wechatwork.customer.domain.ArtemisConstant;
import com.weimob.mcloud.wechatwork.customer.domain.CustomerTouchInfo;
import com.weimob.mcloud.wechatwork.customer.enums.TouchTaskTypeEnum;
import com.weimob.mcloud.wechatwork.customer.es.CustomerLoseFinalTouchSearch;
import com.weimob.mcloud.wechatwork.customer.es.dto.CustomerLoseFinalTouchBiEO;
import com.weimob.mcloud.wechatwork.customer.service.impl.ArtemisService;
import com.weimob.soa.common.response.SoaResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;


@Slf4j
@Service
public class CustomerLoseHandler {

    @Autowired
    private CustomerLoseFinalTouchSearch customerLoseFinalTouchSearch;

    @Reference
    private CustomerLoseService customerLoseService;

    @Reference
    private PrivateSphereService privateSphereService;

    @Resource
    private TaskService taskService;

    @Autowired
    Map<String, CustomerTouchService> customerTouchServiceMap;

    /**
     * 企微助手产品id
     */
    @Value("${aewc.productId:203}")
    private Long aewcProductId;

    @Resource
    private ArtemisService artemisService;

    /**
     * 延迟队列的间接灰度方案使用，当延迟队列支持灰度后，可直接消费延迟队列
     *
     * 背景：延迟队列不支持灰度，Artemis支持灰度
     * 临时灰度实现方案：将接收到的延迟队列消息打上灰度标，再转发到Artemis，以此实现延迟队列的间接灰度
     *
     * 为减少理解成本和风险，需要做到
     * 1、延迟队列的topic名称和Artemis的topic名称保持一致
     * 2、延迟队列的消息体和Artemis的消息体保持一致
     * 3、延迟队列处理方法的入参和逻辑不改动，方便在延迟队列支持灰度后直接切换
     */
    @DqListener(topic = DqConfig.CUSTOMER_LOSE_MSG)
    public void customerLoseHandlerHacker(MsgPoolEntity msgPoolEntity) {
        if (null == msgPoolEntity) {
            return;
        }
        CustomerLoseLog customerLoseLog = this.getPushDqQueueModel(msgPoolEntity);
        if (null == customerLoseLog) {
            log.error("CustomerLoseLog is null. MsgPoolEntity:{}", JSON.toJSONString(msgPoolEntity));
            return;
        }
        log.info("customerLoseHandlerHacker receive customerId:{},orgUserId:{}", customerLoseLog.getCustomerId(), customerLoseLog.getOrgUserId());
        if (StringUtils.isBlank(customerLoseLog.getPrivateSphereId())) {
            log.error("CustomerLoseLog is illegal. CustomerLoseLog:{}", JSON.toJSONString(customerLoseLog));
            return;
        }

        PrivateSphere soaRequest = new PrivateSphere();
        soaRequest.setPrivateSphereId(customerLoseLog.getPrivateSphereId());
        soaRequest.setProductId(aewcProductId);
        SoaResponse<PrivateSphere, Void> soaResponse;
        try {
            soaResponse = this.privateSphereService.fetch(soaRequest);
        } catch (Exception e) {
            log.error("PrivateSphereService.fetch error. SoaRequest:{} errorMessage:{}", JSON.toJSONString(soaRequest), e.getMessage());
            throw e;
        }
        if (null == soaResponse || null == soaResponse.getResponseVo()) {
            log.warn("SoaResponse is illegal. SoaRequest:{} SoaResponse:{}", JSON.toJSONString(soaRequest), JSON.toJSONString(soaResponse));
            return;
        }
        if (null == soaResponse.getResponseVo().getBosId()) {
            log.error("PrivateSphere is illegal. PrivateSphere:{}", JSON.toJSONString(soaResponse.getResponseVo()));
            return;
        }

        this.push(soaResponse.getResponseVo().getBosId(), msgPoolEntity);
    }

    /**
     * 将延迟队列消息打上灰度标，原样推送至Artemis
     *
     * 延迟队列的间接灰度方案使用，当延迟队列支持灰度后，可直接消费延迟队列
     */
    @SubEnvExposePoint
    @SubEnvTagExtractor(key = "weimob-bosid", value = "#args[0]")
    public void push(long bosId, MsgPoolEntity msgPoolEntity) {
        ArtemisBaseInfo<MsgPoolEntity> artemisBaseInfo = new ArtemisBaseInfo<>();
        artemisBaseInfo.setTopic(DqConfig.CUSTOMER_LOSE_MSG);
        artemisBaseInfo.setProducer(ArtemisConstant.USER);
        artemisBaseInfo.setEvent(msgPoolEntity);

        boolean success = this.artemisService.sendToArtemis(artemisBaseInfo);
        if (success) {
            log.info("ArtemisProducer send message success. bosId:{} ArtemisBaseInfo:{}", bosId, JSON.toJSONString(artemisBaseInfo));
        }
    }

    /**
     * 接收带灰度标的Artemis消息，并调用原延迟队列处理方法
     *
     * 延迟队列的间接灰度方案使用，当延迟队列支持灰度后，可直接消费延迟队列
     */
    @ArtemisMessageListener(value = @Subscribe(topic = DqConfig.CUSTOMER_LOSE_MSG, user = ArtemisConstant.CONSUMER_USER))
    public void pull(ArtemisMessages artemisMessages) {
        if (CollectionUtils.isEmpty(artemisMessages)) {
            return;
        }

        for (ArtemisMessage artemisMessage : artemisMessages) {
            if (null == artemisMessage) {
                continue;
            }

            this.customerLoseHandler(JSON.parseObject(artemisMessage.getValue(), MsgPoolEntity.class));
        }
    }

    public void customerLoseHandler(MsgPoolEntity msgClientEntity) {
        log.info("customerLoseHandler msg:{}", JSON.toJSONString(msgClientEntity));
        CustomerLoseLog customerLoseLog = this.getPushDqQueueModel(msgClientEntity);
        if (customerLoseLog == null) {
            return;
        }
        doFinalTouchMsg(customerLoseLog);
    }

    private void doFinalTouchMsg(CustomerLoseLog customerLoseLog) {

        PrivateSphere privateSphereRequest = new PrivateSphere();
        privateSphereRequest.setPrivateSphereId(customerLoseLog.getPrivateSphereId());
        privateSphereRequest.setProductId(aewcProductId);
        SoaResponse<PrivateSphere, Void> fetchPrivateSphere = privateSphereService.fetch(privateSphereRequest);
        if (Objects.isNull(fetchPrivateSphere) || Objects.isNull(fetchPrivateSphere.getResponseVo())) {
            log.warn("doFinalTouchMsg privateSphere is null,privateSphereId:{}", customerLoseLog.getPrivateSphereId());
            return;
        }
        PrivateSphere privateSphere = fetchPrivateSphere.getResponseVo();

        String lastTouchInformation = null;

        CustomerLoseFinalTouchBiEO eo = new CustomerLoseFinalTouchBiEO();
        eo.setPrivateSphereId(customerLoseLog.getPrivateSphereId());
        eo.setCustomerId(customerLoseLog.getCustomerId());
        eo.setOrgUserId(customerLoseLog.getOrgUserId());
        eo.setEndTouchTime(customerLoseLog.getLoseTime());
        // 分页信息
        PageRequest pageRequest = PageRequest.of(eo.getPage(), eo.getPageSize(), Sort.by(
                Sort.Order.desc("touchTime")
        ));
        Page<CustomerLoseFinalTouchBiEO> customerLoseFinalTouchBiEOS = customerLoseFinalTouchSearch.queryByPage(pageRequest, eo);
        if (!CollectionUtils.isEmpty(customerLoseFinalTouchBiEOS.getContent())) {
            CustomerLoseFinalTouchBiEO customerLoseFinalTouchBiEO = customerLoseFinalTouchBiEOS.getContent().get(0);
            if (customerLoseFinalTouchBiEO.getTaskId() != null && customerLoseFinalTouchBiEO.getTouchType() != null) {

                TouchTaskTypeEnum enumByCode = TouchTaskTypeEnum.getEnumByCode(customerLoseFinalTouchBiEO.getTouchType());
                if (enumByCode != null) {
                    CustomerTouchService customerTouchService = customerTouchServiceMap.get(enumByCode.getImplClassName());
                    CustomerTouchInfo touchInfoRequest = new CustomerTouchInfo();
                    touchInfoRequest.setTaskId(customerLoseFinalTouchBiEO.getTaskId());
                    touchInfoRequest.setEcVid(customerLoseFinalTouchBiEO.getEcvid());
                    CustomerTouchInfo customerTouchInfo = customerTouchService.getCustomerTouchInfo(privateSphere, touchInfoRequest);
                    if (customerTouchInfo == null) {
                        log.warn("未找到对应的最后一次触达信息,taskId:{}", customerLoseFinalTouchBiEO.getTaskId());
                        return;
                    }
                    lastTouchInformation = customerTouchInfo.getTaskName();
                }
            }
            customerLoseLog.setLastTouchInformation(lastTouchInformation);
            customerLoseLog.setLastTouchTime(customerLoseFinalTouchBiEO.getTouchTime());
            customerLoseLog.setLastTouchType(customerLoseFinalTouchBiEO.getTouchType());
            log.info("updateCustomerLoseLog request:{}", JSON.toJSONString(customerLoseLog));
            SingleRequest<CustomerLoseLog> request = new SingleRequest(customerLoseLog);
            request.setPrivateSphere(privateSphere);
            customerLoseService.update(request);
        }
    }


    /**
     * 获取延迟队列消息并对象转换
     */
    private CustomerLoseLog getPushDqQueueModel(MsgPoolEntity msgClientEntity) {
        String body = msgClientEntity.getBody();
        if (org.apache.commons.lang3.StringUtils.isBlank(body)) {
            return null;
        }
        CustomerLoseLog customerLoseLog;
        try {
            customerLoseLog = JSON.parseObject(body, CustomerLoseLog.class);
        } catch (Exception e) {
            log.error("handlerConsumer json parse fail,msgClientEntity:{},case by:{}", JSON.toJSONString(msgClientEntity), e.getMessage());
            return null;
        }
        return customerLoseLog;
    }
}
